package net.sf.rose.file.excel.poi;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.List;
import java.util.Map;

import net.sf.rose.file.excel.poi.model.SheetModel;
import net.sf.rose.util.RoseRuntimeException;

/**
 * 功能：利用POI控件根据指定格式的模板文件读写Excel文件
 * 支持.xls和.xlsx二种Excel文件格式
 * @author fengjian
 * @since 2018/12/19
 */
public abstract class ExcelUtils {

    /**
     * 功能：根据模板文件名返回Excel操作工具类
     * @param template 模板文件对象
     * @return 工具类实体对象
     */
	public static ExcelUtils getTool(File template) {
		ExcelUtils excel = null;
		String name = template.getName();
		excel = name.endsWith(".xls") ? new Excel2003() : new Excel2007();
		excel.setBookModelFile(template);
		return excel;
    }

    /**
     * 功能：设置Excel表格的数据模板
     * @param model - 数据模板
     */
	public abstract void addSheetModel(SheetModel model);

    /**
     * 功能：设置Excel模板文件
     * @param template - 模板文件
     * @return 是否加载成功
     */
    public abstract boolean setBookModelFile(File template);

    /**
	 * 功能：加载要读取数据的源文件
	 * @param in 源文件流
	 * @return 是否成功
	 */
	public abstract boolean readFile(InputStream in);

    /**
	 * 功能：加载要读取数据的源文件
	 * @param file 源文件
	 * @return 是否成功
	 */
    public boolean readFile(File file) {
        try {
            return readFile(new FileInputStream(file));
        } catch (Exception e) {
            throw new RoseRuntimeException(e);
        }
    }

    /**
	 * 功能：设置当前要编辑的表格名称
	 * @param sheetName - 表格名称
	 */
	public abstract void setCurrentSheetName(String sheetName);

    /**
	 * 功能：从Excel表格中提取实体对象的属性值
	 * @param bean - 要加载属性的实体对象
	 */
	public abstract void getDataBean(Object bean);

    /**
	 * 功能：从Excel表格中提取实体对象的属性值数组
	 * @param clazz - 要加载属性的类
	 */
	public abstract <T> List<T> getListBean(Class<?> clazz);

    /**
	 * 功能：根据提供的Excel模板文件和要导入数据的源文件，读取数据
	 * @param in  - 源文件流
	 * @param map - 加载的对象集合
	 * @return 是否成功
	 */
	public abstract boolean read(InputStream in, Map<String, Object> map);

    /**
	 * 功能：根据提供的Excel模板文件和要导入数据的源文件，读取数据
	 * @param in  - 源文件
	 * @param map - 加载的对象集合
	 * @return 是否成功
	 */
    public boolean read(File file, Map<String, Object> map) {
        try {
            return read(new FileInputStream(file), map);
        } catch (Exception e) {
            throw new RoseRuntimeException(e);
        }
    }

    /**
	 * 功能：根据模板文件最后一列单元格格式往右复制单元格模板
	 * @param columnMap - 标题容器，Key为属性名，Value为单元格标题
	 */
	public abstract void setDynamicColumns(Map<String, String> columnMap);

    /**
	 * 功能：根据模板文件指定列名所在的列单元格格式往右插入单元格模板
	 * @param key       - 要替换的列名
	 * @param columnMap - 标题容器，Key为属性名，Value为单元格标题
	 */
	public abstract void setDynamicColumns(String key, Map<String, String> columnMap);

    /**
	 * 功能：将数据写入当前的数据表格中
	 * @param data - 要写入的数据容器集合，可以是对象或Map容器
	 */
	public abstract void setData(Object data);

    /**
	 * 功能：将列表数据写入当前的数据表格中
	 * @param list - 要写入的数据列表
	 */
	public abstract void setDataList(List<?> list);

    /**
     * 功能：生成目标Excel文件
     * @param out - 目标文件流
     * @return 成功返回true，否则false
     */
    public abstract boolean write(OutputStream out);

    /**
     * 功能：生成目标Excel文件
     * @param out - 目标文件
     * @return 是否成功
     */
    public boolean write(File out) {
        try {
			return write(new FileOutputStream(out));
		} catch (Exception e) {
			throw new RoseRuntimeException(e);
		}
	}

    /**
     * 功能：根据提供的Excel模板文件和目标文件保存路径，生成目标Excel文件
     * @param out - 目标文件流
     * @param map - 源数据
     * @return 是否成功
     */
    public abstract boolean write(OutputStream out, Map<String, Object> map);

    /**
     * 功能：根据提供的Excel模板文件和目标文件保存路径，生成目标Excel文件
     * @param out - 目标文件
     * @param map - 源数据
     * @return 是否成功
     */
    public boolean write(File out, Map<String, Object> map) {
		try {
			return write(new FileOutputStream(out), map);
		} catch (Exception e) {
			throw new RoseRuntimeException(e);
		}
	}

}
